#pragma once
#include "Log.hpp"
#include "InetAddr.hpp"
#include "Common.hpp"
#include <cstdint>
#include <cstdlib>
#include <memory>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>

namespace SocketModule {
    using namespace LogModule;
    const static int defaultbacklog = 16; // 全连接队列最大长度
    class Socket {
        public:
            virtual ~Socket() {};
            virtual void SocketOrDie() = 0;
            virtual void BindOrDie(uint16_t port) = 0;
            virtual void ListenOrDie(int backlog) = 0;
            virtual std::shared_ptr<Socket> Accept(InetAddr* client) = 0;
            virtual void Close() = 0;
            virtual int Recv(std::string* out) = 0;
            virtual int Send(const std::string& message) = 0;
            virtual int Connect(const std::string& ip, uint16_t port) = 0;
        public:
            void BuildTcpSocketMethod(uint16_t port, int backlog = defaultbacklog) {
                SocketOrDie();
                BindOrDie(port);
                ListenOrDie(backlog);
            }
            void BuildTcpClientSocketMethod() {
                SocketOrDie();
            }
    };
    const static int defaultsockfd = -1;
    class TcpSocket : public Socket {
        public:
            TcpSocket() : _sockfd(defaultsockfd) {}
            TcpSocket(int fd) : _sockfd(fd) {}
            ~TcpSocket() {}
            void SocketOrDie() override {
                _sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
                if(_sockfd < 0) {
                    LOG(LogLevel::FATAL) << "socket error";
                    exit(SOCKET_ERR);
                }
                LOG(LogLevel::INFO) << "socket success";
            }
            void BindOrDie(uint16_t port) override {
                InetAddr localaddr(port);
                int n = ::bind(_sockfd, localaddr.NetAddrPtr(), localaddr.NetAddrLen());
                if(n < 0) {
                    LOG(LogLevel::FATAL) << "bind error";
                    exit(BIND_ERR);
                }
                LOG(LogLevel::INFO) << "bind success";
            }
            void ListenOrDie(int backlog = defaultbacklog) override {
                int n = ::listen(_sockfd, backlog);
                if(n < 0) {
                    LOG(LogLevel::FATAL) << "listen error";
                    exit(LISTEN_ERR);
                }
                LOG(LogLevel::INFO) << "listen success";
            }
            std::shared_ptr<Socket> Accept(InetAddr* client) override {
                struct sockaddr_in peer;
                socklen_t len = sizeof(peer);
                int fd = ::accept(_sockfd, CONV(peer), &len);
                if(fd < 0) {
                    LOG(LogLevel::WARNING) << "accept warning";
                    return nullptr;
                }
                client->SetAddr(peer);
                return std::make_shared<TcpSocket>(fd);
            }
            void Close() override {
                if(_sockfd > 0) {
                    ::close(_sockfd);
                }
            }
            int Recv(std::string* out) override {
                char buffer[1024];
                int n = ::recv(_sockfd, buffer, sizeof(buffer) - 1, 0);
                if(n > 0) {
                    buffer[n] = '\0';
                    *out += buffer; // 这里是可以的operator了
                }
                return n;
            }
            int Send(const std::string& message) override{
                return ::send(_sockfd, message.c_str(), message.size(), 0);
            }
            int Connect(const std::string& ip, uint16_t port) override {
                InetAddr server(ip, port);
                return connect(_sockfd, server.NetAddrPtr(), server.NetAddrLen());
            }
        private: 
            int _sockfd;
    };
}